package com.circle.rest.core.util;

import com.circle.rest.core.exception.ServiceException;
import com.circle.rest.modular.qrtz.listener.GlobalJobListener;
import com.circle.rest.modular.qrtz.listener.GlobalSchedulerListener;
import com.circle.rest.modular.qrtz.listener.GloballTriggerListener;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;

/**
 * @program: RestfulApi
 * @description: 定时任务工具类
 * @author: 赵航
 * @create: 2019-04-12 10:00
 **/
@Component
public final class SchedulerUtil {
    @Autowired
    private Scheduler schedulerDouble;

    private static Scheduler scheduler;

    private static final String group = "RestfulApi";

    @PostConstruct
    public void init() {
        scheduler = schedulerDouble;
    }

    /**
     * 创建Schedule
     *
     * @param jobClass           执行任务的类
     * @param jobName            任务名称
     * @param cron               克隆表达式   不能为空
     * @param startTime          任务开始时间 不能为空
     * @param endTime            任务结束时间 不能为空
     * @param intervalInSeconds  执行间隔时间
     * @param triggerRepeatCount 执行次数为此数字+1
     * @throws Exception 异常抛出
     */
    public static void createSchedule(Class<? extends Job> jobClass,
                                      String jobName,
                                      String cron,
                                      Date startTime,
                                      Date endTime,
                                      Integer intervalInSeconds,
                                      Integer triggerRepeatCount) throws Exception {
        //创建任务
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, group).build();
        Trigger trigger;
        if (ToolUtil.isEmpty(cron)) {
            //SimpleSchedule
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder
                    .simpleSchedule()
                    .withIntervalInSeconds(intervalInSeconds)
                    .withRepeatCount(triggerRepeatCount - 1)
                    .withMisfireHandlingInstructionNowWithRemainingCount();
            trigger = TriggerBuilder.newTrigger().withIdentity(jobName, group)
                    .startAt(startTime)
                    .endAt(endTime)
                    .withSchedule(simpleScheduleBuilder)
                    .build();
        } else {
            //CronSchedule
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
                    .cronSchedule(cron)
                    .withMisfireHandlingInstructionDoNothing();
            trigger = TriggerBuilder.newTrigger().withIdentity(jobName, group)
                    .withSchedule(cronScheduleBuilder)
                    .startAt(startTime)
                    .endAt(endTime)
                    .build();
        }
        scheduler.getListenerManager().addTriggerListener(new GloballTriggerListener());
        scheduler.getListenerManager().addJobListener(new GlobalJobListener());
        scheduler.getListenerManager().addSchedulerListener(new GlobalSchedulerListener());
        //将触发器与任务绑定到调度器内
        scheduler.scheduleJob(jobDetail, trigger);
    }


    /**
     * 修改Schedule
     *
     * @param jobName            任务名称
     * @param cron               克隆表达式   不能为空
     * @param startTime          任务开始时间 如果为null则继承原开始时间
     * @param endTime            任务结束时间 如果为null则继承原结束时间
     * @param intervalInSeconds  执行间隔时间
     * @param triggerRepeatCount 执行次数为此数字+1
     * @throws Exception 异常抛出
     */
    public static void editSchedule(String jobName,
                                    String cron,
                                    Date startTime,
                                    Date endTime,
                                    Integer intervalInSeconds,
                                    Integer triggerRepeatCount) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, group);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());

        if (startTime.compareTo(new Date()) < 0) {
            startTime = new Date();
        }

        if (ToolUtil.isEmpty(cron)) {
            //SimpleSchedule
            SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
            if (ToolUtil.isEmpty(trigger)) {
                throw new ServiceException("此任务已经执行完毕,请重新开始");
            }
            if (ToolUtil.isEmpty(startTime)) {
                startTime = trigger.getStartTime();
            }
            if (ToolUtil.isEmpty(endTime)) {
                endTime = trigger.getEndTime();
            }
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInSeconds(intervalInSeconds)
                    .withRepeatCount(triggerRepeatCount)
                    .withMisfireHandlingInstructionNowWithRemainingCount();
            trigger = trigger.getTriggerBuilder().withIdentity(jobName, group)
                    .startAt(startTime)
                    .endAt(endTime)
                    .withSchedule(simpleScheduleBuilder)
                    .build();
            scheduler.rescheduleJob(triggerKey, trigger);
        } else {
            //CronSchedule
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (ToolUtil.isEmpty(trigger)) {
                throw new ServiceException("此任务已经执行完毕,请重新开始");
            }
            if (ToolUtil.isEmpty(startTime)) {
                startTime = trigger.getStartTime();
            }
            if (ToolUtil.isEmpty(endTime)) {
                endTime = trigger.getEndTime();
            }
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(cron)
                    .withMisfireHandlingInstructionDoNothing();
            // 按新的cron表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder)
                    .startAt(startTime)
                    .endAt(endTime)
                    .build();
            scheduler.rescheduleJob(triggerKey, trigger);
        }

    }

    /**
     * 暂停或者启动Schedule
     *
     * @param jobName 任务名称
     * @throws Exception 异常抛出
     */
    public static void pauseOrResumeSchedule(String jobName)
            throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, group);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
        if (triggerState == Trigger.TriggerState.PAUSED) {
            scheduler.resumeTrigger(triggerKey);
        } else if (triggerState == Trigger.TriggerState.NORMAL) {
            scheduler.pauseTrigger(triggerKey);
        } else if (triggerState == Trigger.TriggerState.NONE
                || triggerState == Trigger.TriggerState.COMPLETE
                || triggerState == Trigger.TriggerState.ERROR
                || triggerState == Trigger.TriggerState.BLOCKED) {
            throw new ServiceException("任务不在可控状态");
        }

    }

    /**
     * 删除Schedule
     *
     * @param jobName 任务名称
     * @throws Exception 异常抛出
     */
    public static void removeSchedule(String jobName) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, group);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
        scheduler.pauseTrigger(triggerKey);// 停止触发器
        scheduler.unscheduleJob(triggerKey);// 移除触发器
        scheduler.deleteJob(JobKey.jobKey(jobName, group));// 删除任务

    }

    /**
     * 获取任务状态
     *
     * @param jobName 任务名称
     * @return Trigger.TriggerState
     * @throws Exception 异常抛出
     */
    public static Trigger.TriggerState getTriggerState(String jobName) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, group);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
        return scheduler.getTriggerState(triggerKey);
    }

    /**
     * 启动所有定时任务
     */
    public static void startAllSchedule() {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭所有定时任务
     */
    public static void shutDownAllSchedule() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
